--- 模块功能：HTTPDNS 域名转地址
-- @module socket
-- @author openLuat
-- @license MIT
-- @copyright openLuat
-- @release 2017.9.25
require "ril"
require "misc"
require "socket"
require "http"
module(..., package.seeall)

local group = {
    "114.114.114.114", -- 114 DNS
    "114.114.115.115",
    "223.5.5.5", --阿里 DNS
    "223.6.6.6",
    "119.29.29.29", -- 腾讯 DNS
    "182.254.116.116",
    "1.2.4.8", -- 中国互联网中心 DNS
    "180.76.76.76", -- 百度 DNS
    "208.67.220.220", -- Open DNS
    "8.8.8.8", -- 谷歌 DNS
}
-- 回调函数库
local callbacks = {}

--- 添加DNS服务器
-- @string ...：DNS 服务器地址字符串,用","号隔开
-- @return nil
-- @usage dns.addServer("114.114.114.114","114.114.115.115")
function addServer(...)
    for i = 1, #arg do
        table.insert(group, arg[i])
    end
end
--- 返回DNS服务器table
-- @return table：DNS的table
-- @usage dns.getServers()
function getServers()
    return group
end
--- 设置模块的DNS
-- @string primary：主 DNS 服务器地址字符串
-- @string secondary：从 DNS 服务器地址字符串
-- @return nil
-- @usage dns.setDNS("114.114.114.114","114.114.115.115")
function setDNS(primary, secondary)
    ril.request("AT*NETDNS=5," .. (primary or "") .. "," .. (secondary or ""))
    ril.request("AT*NETDNS=5")
end
--- dns.on 注册函数
-- @string event,事件，建议值为域名
-- @function callback,回调方法，形参：返回的IP地址address。
-- @usage mt.on("www.yyia.top",function(addr) local address = addr end)
function on(event, callback)
    callbacks[event] = callback
end

---将域名解析为IP地址
-- 目前HTTPDNS使用腾讯服务。如果有更多DNS，会自动添加。
-- @string addr：域名
-- @return nil: 非线程使用，返回nil,需要使用dns.on()注册回调函数
-- @return string: 线程中使用,解析成功返回IP地址，如果失败返回 false
-- @usage local addr = dns.request("www.yyia.top")
function request(domain, timeout, dnsname)
    if not socket.isReady() then
        log.warn("socket.connect: ip not ready")
        return domain
    end
    if dnsname then table.insert(group, 1) end
    coroutine.resume(coroutine.create(function()
        local names, body, ip = domain:split("."), "", false
        local transID = misc.getImei():sub(-4, -1):fromHex()
        local head = string.fromHex("01 00 00 01 00 00 00 00 00 00")
        local tail = string.fromHex("00 00 01 00 01")
        for i = 1, #names do
            body = body .. string.char(#names[i]) .. names[i]
        end
        for i = 1, #group do
            local c = socket.udp()
            if c:connect(group[i], 53) then
                if c:send(transID .. head .. body .. tail) then
                    local r, s = c:recv(5000)
                    if r and s:toHex():sub(8, 8) == "0" then
                        ip = table.concat({s:byte(-4, -1)}, ".")
                    end
                end
            end
            c:close()
            if ip then break end
        end
        if callbacks[domain] then callbacks[domain](ip) end
        sys.publish("DNS_REQ_END_" .. domain, ip)
    end))
    if coroutine.running() then
        local res, addr = sys.waitUntil("DNS_REQ_END_" .. domain, timeout or 30000)
        return res and addr or false
    end
end

--- 使用HTTPDNS将域名解析为IP地址支持,当前使用腾讯免费服务
-- @string addr：域名
-- @return nil: 非线程使用，返回nil,需要使用dns.on()注册回调函数
-- @return string: 线程中使用,解析成功返回IP地址，如果失败返回 false
-- @usage local addr = dns.httpDNS(www.163.com)
function httpDNS(domain, timeout)
    sys.taskInit(function(domain)
        local code, head, body, ip = http.request("GET", "http://119.29.29.29/d", timeout or 10000, {dn = domain}, nil, 1)
        -- 先请求HTTPDNS
        if (code == "200" or code == "206") and body:match("^([%d%.]+)") then
            ip = body:match("^([%d%.]+)")
        end
        if callbacks[domain] then callbacks[domain](ip) end
        sys.publish("HTTPDNS_REQ_END_" .. domain, ip)
    end, domain)
    if coroutine.running() then
        local res, address = sys.waitUntil("HTTPDNS_REQ_END_" .. domain)
        return res and address or false
    end
end
